home *** CD-ROM | disk | FTP | other *** search
- // browse2.cpp
- // This program allows you to view the contents of a file.
- // You can display it either in ASCII or hexadecimal format.
- // Once a file is displayed, you can scroll through the
- // file using the cursor pad keys (PgUp, PgDn, and so on). To
- // use the program, issue the following command at the DOS
- // prompt:
- // browse2 <filename>
- //
- // NOTE: COMPILE THIS IN LARGE MODEL ONLY!
- //
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <io.h>
- #include <dir.h>
- #include <dos.h>
-
- #define Screen (*ScreenPtr)
-
- const long MaxBufSize = 65520L; // Roughly 64K maximum file size
- const int TabSize = 5; // Depends on the file
- const unsigned char EscKey = 27; // Extended key codes
- const unsigned char PgUp = 73;
- const unsigned char PgDn = 81;
- const unsigned char Home = 71;
- const unsigned char EndKey = 79;
- const unsigned char UpKey = 72;
- const unsigned char DnKey = 80;
- const unsigned char Alt_S = 31; // The search key
- const unsigned char F1Key = 59; // The buffer switching key
- const unsigned char TabKey = 9;
- const unsigned char CR = 10; // Carriage return
-
- struct Texel { // Structure used for
- char Ch; // direct screen access
- unsigned char Attr; // Character attribute
- };
-
- typedef Texel ScreenArea[25][80]; // The screen
-
- // -------------------- The Screen Class --------------------- //
-
- class ScreenClass {
- public:
- ScreenArea far *ScreenPtr;
- int ScrSize;
- ScreenClass(unsigned Segment, unsigned Offset);
- virtual ~ScreenClass(void) { ; }
- char Get(int X, int Y) { return Screen[Y][X].Ch; }
- void Put(int X, int Y, char Ch, unsigned char Atr);
- void MarkLine(int Row, unsigned char Atr);
- };
-
- // --------------------- The Buffer Class --------------------- //
-
- class Buffer {
- public:
- char *TextPtr, FileName[13];
- unsigned char BuffAlloc;
- int NoBytes, Attr, NumLines, LinePtr[2000];
- long Size;
- ftime Time;
- ffblk ffblk;
- FILE *fp;
- Buffer(void);
- virtual ~Buffer(void) { if (BuffAlloc) free(TextPtr); }
- unsigned char OpenAndRead(char *FName);
- void Dup(Buffer *Buf);
- char GetCh(int Index);
- virtual char *GetLine(char *Str, int Index);
- virtual void SetLines(void);
- int GetNumLines(void) { return NumLines; }
- };
-
- // -------------------- The Hex Buffer Class ------------------ //
-
- class HexBuffer : public Buffer {
- public:
- HexBuffer(void): Buffer() { };
- virtual char *GetLine(char *Str, int Index);
- virtual void SetLines(void);
- };
-
- // ----------------------- The Browser Class ------------------ //
-
- class Browser {
- public:
- ScreenClass *ScrPtr;
- Buffer *MainBuff, *AltBuff;
- int Lc, Bot, End;
- Browser(ScreenClass *Scr, Buffer *Buf1, Buffer *Buf2);
- virtual ~Browser(void) { ; }
- void ProcessInput(char Ch);
- void DisplayFStat(void);
- void DisplayCommands(void);
- void SetLPtr(void);
- void ShowScreen(void);
- void PageUp(void);
- void PageDn(void);
- void LineUp(void);
- void LineDn(void);
- void TopPage(void);
- void BotPage(void);
- void FileSearch(void);
- };
-
- // Miscellaneous support functions
- char *GetStr(char *Str);
- char *ChToHex(char *Str, char Ch);
-
- // ------------------- The Screen Member Functions ---------------- //
-
- ScreenClass::ScreenClass(unsigned Segment, unsigned Offset)
- // Set up the pointer to video memory, and set the size of
- // the screen
- {
- ScreenPtr = (ScreenArea *)(((long)Segment << 16) | (long)Offset);
- ScrSize = 23;
- }
-
- void ScreenClass::Put(int X, int Y, char Ch, unsigned char Atr)
- // Put a character to the screen at the given location
- {
- Screen[Y][X].Ch = Ch;
- Screen[Y][X].Attr = Atr;
- }
-
- void ScreenClass::MarkLine(int Row, unsigned char Atr)
- // Highlight a line on the screen
- {
- int Col;
-
- for (Col=0; Col<80; Col++) Screen[Row][Col].Attr = Atr;
- }
-
- // ------------------- The Buffer Member Functions ---------------- //
-
- Buffer::Buffer(void)
- // At the beginning, no buffer is allocated
- {
- BuffAlloc = 0;
- strcpy(FileName,"");
- }
-
- char Buffer::GetCh(int Index)
- // Returns the specified character from the file buffer if
- // the index is in range. If the index is out of range, a
- // Control-Z (0x1A) is returned.
- {
- return (Index < NoBytes) ? TextPtr[Index] : 0x1A;
- }
-
- unsigned char Buffer::OpenAndRead(char *Fname)
- // Return true if the file Fname is opened and the file data
- // is read okay
- {
- int DosError;
-
- DosError = findfirst(Fname, &ffblk, 0);
- if (DosError != 0) {
- printf("Can't find file %s\n", Fname);
- return 0;
- }
- else {
- if ((fp=fopen(Fname, "r")) == NULL) { // Open file
- printf("The file %s cannot be opened\n", Fname);
- return 0;
- }
- else {
- // Allocate buffer memory
- // CODE CHANGE: Cannot cast to far * if in small memory model
- if ((TextPtr=(char *)malloc(ffblk.ff_fsize)) == NULL) {
- printf("Out of memory\n");
- BuffAlloc = 0;
- return 0;
- }
- else {
- BuffAlloc = 1; // Set flag noting allocation
- // Read file data into buffer
- getftime(fileno(fp), &Time);
- Size = ffblk.ff_fsize;
- if (Size >= MaxBufSize) {
- printf("File is too large\n");
- fclose(fp);
- return 0;
- }
- else {
- NoBytes = read(fileno(fp), TextPtr, ffblk.ff_fsize);
- strcpy(FileName, Fname); // Record the file name
- fclose(fp); // Close the file
- return 1; // Read operation okay
- }
- }
- }
- }
- }
-
- void Buffer::Dup(Buffer *Buf)
- // Duplicate another file buffer. The file attributes are
- // copied, but the file text is not. Instead, we merely point
- // to the text. Since we're not allocating the text buffer,
- // we make sure BuffAlloc is False (0). We'll change the line
- // pointer array, because we might not display lines the same
- // way with this new buffer.
- {
- TextPtr = Buf->TextPtr; // Copy pointers only
- NoBytes = Buf->NoBytes; // Copy file attributes
- Size = Buf->Size;
- Time = Buf->Time;
- BuffAlloc = 0; // Important to do this!
- SetLines(); // Recompute line pointers
- }
-
- char *Buffer::GetLine(char *Str, int Index)
- // Get the specified line from the buffer and return it in a
- // string.
- {
- char Ch;
- int P=0, I;
-
- while ((Ch=GetCh(Index)) != CR && Ch != 0x1A) {
- if (Ch == TabKey) // Look for tab
- for (I=0; I<TabSize; I++)
- Str[P++] = ' ';
- else Str[P++] = Ch;
- Index++;
- }
- Str[P] = '\0'; // Terminate string
- return Str;
- }
-
- void Buffer::SetLines(void)
- // Scan the text for newlines and set the line pointer array
- {
- char Ch;
- int L=0, I;
-
- LinePtr[L++] = 0; // Initialize the index array
- for (I=0; I<NoBytes; I++)
- if ((Ch=GetCh(I)) == CR) LinePtr[L++] = I + 1;
- NumLines = L;
- }
-
- // --------------- The Hex Buffer Member Functions -------------- //
-
- char *HexBuffer::GetLine(char *Str, int Index)
- // Get the specified line from the buffer, returning both hex
- // and ASCII representations.
- {
- char S[3] = " ";
- int I;
-
- strcpy(Str, "");
- for (I=0; I<16; I++) {
- strcat(Str, ChToHex(S, GetCh(Index+I)));
- strcat(Str, " ");
- }
- strcat(Str, "| ");
- for (I=0; I<16; I++) Str[I+50] = GetCh(Index+I);
- Str[66] = '\0';
- return Str;
- }
-
- void HexBuffer::SetLines(void)
- // Set the line pointer array so that each line will point to
- // sixteen characters
- {
- int L, I;
-
- NumLines = Size / 16;
- if (Size % 16 != 0) NumLines++;
- for (I=0, L=0; I<NumLines; I++, L+=16)
- LinePtr[I] = L;
- }
-
- // ------------------ The Browser Member Functions ---------------- //
-
- Browser::Browser(ScreenClass *Scr, Buffer *Buf1, Buffer *Buf2)
- // Initialize the browser by setting up pointers to the
- // screen and to the two buffers
- {
- ScrPtr = Scr; MainBuff = Buf1; AltBuff = Buf2;
- }
-
- void Browser::DisplayFStat(void)
- // Display the first status line of file information
- // including file name, size, date, and time
- {
- char AtStr[8];
-
- // CODE CHANGE: The following lines don't do any good
- // (see last line of function instead)
- // int Col;
- // for (Col=0; Col<80; Col++) // Put status bar in reverse video
- // ScrPtr->Put(Col, 0, ' ', 112);
- // textbackground(7); // Text is set to black on white
- // textcolor(0);
-
- gotoxy(3, 1); // Display filename
- printf("File: %s", MainBuff->FileName);
- gotoxy(26, 1);
- printf("Date: %02u-%02u-%04u", MainBuff->Time.ft_month,
- MainBuff->Time.ft_day, MainBuff->Time.ft_year+1980);
- gotoxy(48, 1);
- printf("Size: %ld", MainBuff->Size); // Display size
- // Display attributes
- if (MainBuff->ffblk.ff_attrib == FA_RDONLY)
- strcpy(AtStr, "R");
- else strcpy(AtStr, "R-W");
- if (MainBuff->ffblk.ff_attrib == FA_HIDDEN)
- strcat(AtStr, "-H");
- if (MainBuff->ffblk.ff_attrib == FA_SYSTEM)
- strcat(AtStr, "-S");
- gotoxy(63, 1);
- printf("Attr: %s", AtStr);
-
- // CODE CHANGE: Added this line
- ScrPtr->MarkLine(0, 112);
- }
-
- void Browser::DisplayCommands(void)
- // Display the command bar at the last line of the screen
- {
- // CODE CHANGE: These lines do no good. See last line instead
- // int Col;
- // for (Col=0; Col<80; Col++) ScrPtr->Put(Col, 24, ' ', 112);
- gotoxy(1, 25);
- printf("<Home=Top> <End=Bot> <PgUp=Prv> <PgDn=Next> "
- "<Alt-S=Search> <Esc=Quit> <F1=Flip>");
- // CODE CHANGE: Added this line
- ScrPtr->MarkLine(24, 112);
- }
-
- void Browser::SetLPtr(void)
- // Set the current and bottom line indices for the screen
- {
- Lc = MainBuff->GetNumLines();
- if (Lc > ScrPtr->ScrSize) // Set the bottom line index
- Bot = Lc - ScrPtr->ScrSize;
- else Bot = 0;
- End = Lc - 1;
- Lc = 0; // Set the top line index
- }
-
- void Browser::ShowScreen(void)
- // Displays a screen image containing 23 lines of the file
- {
- int Row, Col, P, TLc, Length;
- char Str[81];
-
- TLc = Lc; // Start with the current line index
- for (Row=0; Row<ScrPtr->ScrSize && Row<=End; Row++) {
- P = MainBuff->LinePtr[TLc];
- strcpy(Str, MainBuff->GetLine(Str, P));
- Length = strlen(Str);
- for (Col=0; Col<80 && Col<Length; Col++)
- ScrPtr->Put(Col, Row+1, Str[Col], 7);
- for (; Col<80; Col++)
- ScrPtr->Put(Col, Row+1, ' ', 7);
- TLc++;
- }
- for (; Row<ScrPtr->ScrSize; Row++)
- for (Col=0; Col<80; Col++)
- ScrPtr->Put(Col, Row+1, ' ', 7);
- }
-
- void Browser::PageUp(void)
- {
- if (Lc-ScrPtr->ScrSize > 0) Lc -= ScrPtr->ScrSize;
- else Lc = 0;
- ShowScreen();
- }
-
- void Browser::PageDn(void)
- {
- if (Lc+ScrPtr->ScrSize < Bot && Bot >= ScrPtr->ScrSize)
- Lc += ScrPtr->ScrSize;
- else Lc = Bot;
- ShowScreen();
- }
-
- void Browser::LineUp(void)
- {
- if (Lc > 0) {
- Lc--; ShowScreen();
- }
- }
-
- void Browser::LineDn(void)
- {
- if (Lc < Bot && Bot >= ScrPtr->ScrSize) {
- Lc++; ShowScreen();
- }
- }
-
- void Browser::TopPage(void)
- {
- Lc = 0; ShowScreen();
- }
-
- void Browser::BotPage(void)
- {
- if (Bot >= ScrPtr->ScrSize) {
- Lc = Bot; ShowScreen();
- }
- }
-
- void Browser::FileSearch(void)
- // Searches the buffer for a string. If a match is found, the
- // line containing the string is highlighted.
- {
- int Col, I, P;
- char SearchStr[81], *S, Line[81], *Ptr;
-
- for (Col=0; Col<=78; Col++)
- ScrPtr->Put(Col, 24, ' ', 112);
- gotoxy(2, 25);
- printf("Search for: ");
- if ((S=GetStr(SearchStr)) == NULL) { // Get the search string
- DisplayCommands();
- return;
- }
- I = Lc;
- do {
- P = MainBuff->LinePtr[I];
- Col = 0;
- strcpy(Line, MainBuff->GetLine(Line, P));
- Ptr = strstr(Line, S); // Look for a match
- I++;
- } while (Ptr == NULL && I <= End);
-
- if (Ptr != NULL) { // Match found
- if (I > Lc + ScrPtr->ScrSize) {
- Lc = I - ScrPtr->ScrSize;
- ShowScreen();
- }
- ScrPtr->MarkLine(I-Lc, 112); // Highlight line with match
- if (getch() == 0) (void)getch();
- ScrPtr->MarkLine(I-Lc, 7); // Set line back to normal
- }
- DisplayCommands();
- }
-
- void Browser::ProcessInput(char Ch)
- {
- Buffer *TempBuff;
-
- switch (Ch) {
- case PgUp : PageUp(); break;
- case PgDn : PageDn(); break;
- case UpKey : LineUp(); break;
- case DnKey : LineDn(); break;
- case Home : TopPage(); break;
- case EndKey: BotPage(); break;
- case F1Key : // Toggle between the two types of buffers
- TempBuff = MainBuff;
- MainBuff = AltBuff;
- AltBuff = TempBuff;
- SetLPtr(); // Reset top and bottom line indices
- ShowScreen(); // Redisplay the screen
- break;
- case Alt_S : FileSearch(); break;
- }
- }
-
- // ------------------ Other supporting routines --------------- //
-
- unsigned SelectMonitor(void)
- // Determine the type of monitor installed and return the
- // memory address of the installed monitor
- // CODE CHANGE: This function need only return an unsigned value
- {
- struct REGS Regs;
-
- Regs.h.ah = 15;
- int86(0x10, &Regs, &Regs);
- if (Regs.h.al == 7) return 0xB000; // Monochrome
- else return 0xB800; // Graphics
- }
-
- char *GetStr(char *Str)
- // Read a string at the current cursor location
- {
- char Ch;
- int Count=0;
-
- while ((Ch=getch()) != 13 && Ch != EscKey) {
- printf("%c", Ch);
- Str[Count++] = Ch;
- }
- if (Ch == EscKey) return NULL;
- Str[Count] = '\0'; // Terminate string
- return Str;
- }
-
- char *ChToHex(char *Str, char Ch)
- // A support function for HexBuffer than converts a byte into
- // two hex digits
- {
- const char HexDigits[17] = "0123456789ABCDEF";
-
- strncpy(Str, &HexDigits[Ch >> 4], 1); // Create a two character
- strncpy(&Str[1], &HexDigits[Ch & 0x0F], 1); // string
- return Str;
- }
-
- // ------------------------- Main Program -------------------- //
-
- main(int argc, char *argv[])
- {
- char Ch;
- ScreenClass *ScreenObj;
- Browser *BrowseObj;
- Buffer *BufObj;
- HexBuffer *HexBufObj;
-
- clrscr();
- if (argc != 2) {
- printf("Incorrect number of arguments.\n");
- printf("To browse a file use the command:\n");
- printf("\tbrowse2 <filename>\n");
- exit(1);
- }
-
- if (!(ScreenObj = new ScreenClass(SelectMonitor(), 0x00))) {
- printf("Not enough memory\n");
- exit(1);
- }
- // Allocate and initialize buffer, read in data. If error
- // reading data, quit.
- if (!(BufObj = new Buffer())) {
- printf("Not enough memory\n");
- exit(1);
- }
- if (!BufObj->OpenAndRead(argv[1])) exit(1);
- BufObj->SetLines();
-
- // Make hex buffer that duplicates what's in the other buffer
- if (!(HexBufObj = new HexBuffer())) {
- printf("Not enough memory\n");
- exit(1);
- }
- HexBufObj->Dup(BufObj);
-
- // Now set up the browser to use the screen and buffer objects
- if (!(BrowseObj = new Browser(ScreenObj, BufObj, HexBufObj))) {
- printf("Not enough memory\n");
- exit(1);
- }
-
- // Draw browser screen, show initial lines
-
- BrowseObj->DisplayFStat();
- BrowseObj->DisplayCommands();
- BrowseObj->SetLPtr();
- BrowseObj->ShowScreen();
-
- do { // Process keys until Esc key pressed
- Ch = getch();
- switch (Ch) {
- case 0: // Extended key pressed
- Ch = getch();
- BrowseObj->ProcessInput(Ch);
- break;
- case EscKey: break;
- default: putch(7); // Illegal key, so sound the bell
- }
- } while (Ch != EscKey);
-
- delete BrowseObj; // Remove objects
- delete BufObj;
- delete HexBufObj;
- delete ScreenObj;
-
- textbackground(0); // Restore screen back to normal
- textcolor(7);
- clrscr();
- }
-
-